package com.right.netty.server;

import com.right.factory.PackageFactory;
import com.right.netty.AbstractConnector;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**********************************************
 * @author pillar
 * @date 2018/3/22
 **********************************************/
@Slf4j
public class Server extends AbstractConnector<ServerConfiguration,ServerBootstrap> {

    private List<Integer> ports = new ArrayList<>();
    public Server addPort(int port){
        ports.add(port);
        return this;
    }
    public Server(int port, PackageFactory packageFactory) {
        super(new ServerConfiguration(), packageFactory);
        setSocketAddress(new InetSocketAddress(port));
    }

    public void start() throws InterruptedException {

        getBootstrap().bind().addListener(
                future -> {
                    final Channel channel = ((ChannelFuture)future).channel();
                    setChannel(channel);
                    log.info("Start is started and listening at {}", channel.localAddress());
                }
        ).sync().await();
    }


    @Override
    protected ServerBootstrap createBootstrap() {
        final ServerBootstrap bootstrap = new ServerBootstrap();

        bootstrap.group(getBossEventLoopGroup(), getWorkerEventLoopGroup())
                .channel(NioServerSocketChannel.class)
                .localAddress(getSocketAddress())
                .childHandler(new ServerChannelInitializer<>(
                        getConfiguration(),
                        getWorkerEventLoopGroup(),
                        getMessageFactory(),
        new ChannelInboundHandlerAdapter[]{getMessageHandler()}));
        for (Integer port : ports){
            bootstrap.bind(new InetSocketAddress(port));
        }
        configureBootstrap(bootstrap);

        bootstrap.validate();

        return bootstrap;
    }
    @Override
    public void shutdown() {
        stop();
        super.shutdown();
    }

    public boolean isStarted() {
        final Channel channel = getChannel();
        return channel != null && channel.isOpen();
    }

    public void stop() {
        final Channel channel = getChannel();
        if (channel == null) {
            throw new IllegalStateException("Start is not started.");
        }
        log.info("Stopping the Start...");
        try {
            channel.deregister();
            channel.close().sync().await(10, TimeUnit.SECONDS);
            log.info("Start was Stopped.");
        } catch (InterruptedException e) {
            log.error("Error while stopping the posp", e);
        }

    }
}
